package com.xingfudazi.app.service.domain;

import com.xingfudazi.acl.cache.CacheClient;
import com.xingfudazi.app.dto.WxJsCode2sessionResponse;
import com.xingfudazi.app.dto.WxRiskResponse;
import com.xingfudazi.app.properties.WxConfigProperties;
import com.xingfudazi.common.exception.ExceptionEnum;
import com.xingfudazi.common.utils.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import javax.validation.constraints.NotBlank;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 微信请求工具领域服务
 *
 * @author YuJiaMing
 * date 2023年11月03日 09:51
 */
@Slf4j
@Component
public class WxRequestService {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private WxConfigProperties wxConfigProperties;


    @Autowired
    private CacheClient cacheClient;


    /**
     * 小程序登录
     * <a href="https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/user-login/code2Session.html">...</a>
     *
     * @param code 前段传递code
     * @return WxJsCode2sessionResponse 登录响应
     */
    public WxJsCode2sessionResponse jsCode2session(@NotBlank String code) {
        String url = "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code";
        String appId = wxConfigProperties.getAppId();
        String appSecret = wxConfigProperties.getAppSecret();
        Map<?, ?> result = get(String.format(url, appId, appSecret, code));
        return new WxJsCode2sessionResponse((String) result.get("session_key"),
                (String) result.get("unionid"),
                (String) result.get("openid"));
    }


    /**
     * 获取手机号
     * <a href="https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/user-info/phone-number/getPhoneNumber.html">...</a>
     *
     * @param code 前端传递code
     * @return 手机号
     */
    public String getPhone(@NotBlank String code) {
        String url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + getToken();
        // 传递code
        Map<String, Object> params = new HashMap<>(1);
        params.put("code", code);
        Map<?, ?> result = post(url, params);
        // 对返回结果进行处理
        Map<?, ?> phoneMap = (Map<?, ?>) result.get("phone_info");
        return (String) phoneMap.get("phoneNumber");
    }


    /**
     *  图片风控
     *  <a href="https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/sec-center/sec-check/mediaCheckAsync.html">...</a>
     *
     *  @param imgurl
     */
    public Map<?, ?> riskImage(@NotBlank String imgurl, @NotBlank String openId) {
        String url = "https://api.weixin.qq.com/wxa/img_sec_check?access_token=" + getToken();
        // 传递参数
        Map<String, Object> params = new HashMap<>(1);
        params.put("content", imgurl);
        params.put("media_type", 2);
        params.put("version", 2);
        params.put("scene", 3);
        params.put("openid", openId);
        Map<?, ?> result = post(url, params);

        return result;
    }

    /**
     *  图片风控
     *  <a href="https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/sec-center/sec-check/mediaCheckAsync.html">...</a>
     *
     *  @param file
     */


    public Map<?, ?> riskImage2(@NotBlank MultipartFile file) throws IOException {
        String url = "https://api.weixin.qq.com/wxa/img_sec_check?access_token=" + getToken();

        // 读取文件内容到字节数组
        byte[] fileBytes = file.getBytes();

        // 创建 MultiValueMap 来保存 form data
        MultiValueMap<String, Object> formData = new LinkedMultiValueMap<>();
        ByteArrayResource resource = new ByteArrayResource(fileBytes) {
            @Override
            public String getFilename() {
                return file.getOriginalFilename();
            }
        };
        formData.add("media", resource);

        // 设置请求头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);

        HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(formData, headers);

        // 发送 POST 请求
        Map<?, ?> result = restTemplate.postForObject(url, requestEntity, Map.class);

        return result;
    }

    public Map<?, ?> riskText(@NotBlank String content, @NotBlank String openId) {
        String url = "https://api.weixin.qq.com/wxa/msg_sec_check?access_token=" + getToken();
        // 传递参数
        Map<String, Object> params = new HashMap<>(1);
        params.put("content", content);
        params.put("version", 2);
        params.put("scene", 1);
        params.put("openid", openId);
        Map<?, ?> result = post(url, params);

        return result;
    }


    /**
     * 获取token
     * <a href="https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/mp-access-token/getAccessToken.html">...</a>
     *
     * @return token
     */
    public String getToken() {
        // 缓存
        String tokenKey = "wx-access";
        String cacheToken = cacheClient.getCacheObject(tokenKey);
        if (cacheToken != null) {
            return cacheToken;
        }

        // 请求
        String appId = wxConfigProperties.getAppId();
        String appSecret = wxConfigProperties.getAppSecret();
        String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";
        Map<?, ?> result = get(String.format(url, appId, appSecret));
        String accessToken = (String) result.get("access_token");
        int expiresIn = (Integer) result.get("expires_in");

        // 存储缓存并返回
        cacheClient.setCacheObject(tokenKey, accessToken, expiresIn - 500, TimeUnit.SECONDS);
        return accessToken;
    }


    Map<?, ?> get(String url) {
        Map<?, ?> result = JSONUtil.toBean(restTemplate.getForObject(url, String.class),Map.class);
        log.info("微信请求结果为 {}", JSONUtil.toJsonStr(result));

        if (result == null || "0".equals(result.get("errcode"))) {
            throw ExceptionEnum.WX_REQUEST_EXCEPTION.unwrap();
        }
        return result;
    }


    Map<?, ?> post(String url, Map<String, Object> params) {
        // 请求头
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Type", "application/json");
        HttpEntity<String> request = new HttpEntity<>(JSONUtil.toJsonStr(params), headers);
        Map<?, ?> result = restTemplate.postForObject(url, request, Map.class);
        log.info("微信请求结果为 {}", JSONUtil.toJsonStr(result));

        if (result == null || "0".equals(result.get("errcode"))) {
           throw  ExceptionEnum.WX_REQUEST_EXCEPTION.unwrap();
        }
        return result;
    }

}
